Frame popup support and some small fixes
authorBar Magal <barmagal@gmail.com>
Mon, 6 Jul 2015 10:46:46 +0000 (13:46 +0300)
committerBar Magal <barmagal@gmail.com>
Mon, 6 Jul 2015 10:46:46 +0000 (13:46 +0300)
Summary of changes:
- add emacs 24.3 as a dependency, because
  `display-buffer-in-major-side-window` doesn't exist in older emacsen
- add option to show which-key buffer in a popup frame
  `(setq which-key-popup-type 'frame)`
- stop close timer when disabling which-key-mode
- don't hide which-key buffer before showing it. instead, show methods
  handle the case that the buffer is already shown
- `which-key/hide-popup` calls function depending on popup
  type (similar to `which-key/show-popup`)
- use `display-buffer-in-major-side-window` instead of
  `display-buffer-in-side-window`, for popup type side-window. ensures
  new side window is created properly even if other side windows already
  exist.
- erase previous contents of which-key buffer before inserting new
  contents, and adjust buffer display in window by moving point to
  the buffer's beginning

which-key.el

index 5a03fcbc846577ecc1c534b63a6bed9299a3c85c..0230aad242d3a55163a6e3b27fa56741da15e209 100644 (file)
@@ -6,7 +6,7 @@
 ;; URL: https://github.com/justbur/which-key/
 ;; Version: 0.1
 ;; Keywords:
-;; Package-Requires: ((s "1.9.0") (popwin "1.0.0"))
+;; Package-Requires: ((emacs "24.3") (s "1.9.0") (popwin "1.0.0"))
 
 ;;; Commentary:
 ;;
@@ -49,6 +49,10 @@ location is left or right.")
 (defvar which-key-side-window-max-height 20
   "Maximum height of which-key popup when type is side-window and
 location is top or bottom.")
+(defvar which-key-frame-max-width 60
+  "Maximum width of which-key popup when type is frame.")
+(defvar which-key-frame-max-height 20
+  "Maximum height of which-key popup when type is frame.")
 ;; (defvar which-key-display-method 'minibuffer
 ;;   "Controls the method used to display the keys. The default is
 ;; minibuffer, but other possibilities are 'popwin and
@@ -73,6 +77,9 @@ location is top or bottom.")
   "Internal: Holds reference to close window timer.")
 (defvar which-key--setup-p nil
   "Internal: Non-nil if which-key buffer has been setup.")
+(defvar which-key--frame nil
+  "Internal: Holds reference to which-key frame.
+Used when `which-key-popup-type' is 'popup.")
 
 ;;;###autoload
 (define-minor-mode which-key-mode
@@ -87,7 +94,8 @@ location is top or bottom.")
         (which-key/start-open-timer))
     (remove-hook 'focus-out-hook 'which-key/stop-open-timer)
     (remove-hook 'focus-in-hook 'which-key/start-open-timer)
-    (which-key/stop-open-timer)))
+    (which-key/stop-open-timer)
+    (which-key/stop-close-timer)))
 
 (defun which-key/setup ()
   "Create buffer for which-key."
@@ -131,7 +139,9 @@ Finally, show the buffer."
     (if (> (length key) 0)
         (progn
           (which-key/stop-close-timer)
-          (which-key/hide-popup)
+          ;; remove this because `which-key/show-popup' should be able to
+          ;; handle the case where which-key buffer is already displayed
+          ;; (which-key/hide-popup)
           (let* ((buf (current-buffer))
                  ;; get formatted key bindings
                  (fmt-width-cons (which-key/get-formatted-key-bindings buf key))
@@ -154,8 +164,23 @@ Finally, show the buffer."
 ;;     (delete-window which-key--window)))
 
 (defun which-key/hide-popup ()
+  (cl-case which-key-popup-type
+    (minibuffer (which-key/hide-buffer-minibuffer))
+    (side-window (which-key/hide-buffer-side-window))
+    (frame (which-key/hide-buffer-frame))))
+
+(defun which-key/hide-buffer-minibuffer ()
+  nil)
+
+(defun which-key/hide-buffer-side-window ()
   (when (buffer-live-p which-key--buffer)
-    (delete-windows-on which-key--buffer)))
+    ;; in case which-key buffer was shown in an existing window, `quit-window'
+    ;; will re-show the previous buffer, instead of closing the window
+    (quit-windows-on which-key--buffer)))
+
+(defun which-key/hide-buffer-frame ()
+  (when (frame-live-p which-key--frame)
+    (delete-frame which-key--frame)))
 
 (defun which-key/show-popup (act-popup-dim)
   "Show guide window. ACT-POPUP-DIM includes the
@@ -164,7 +189,8 @@ in the popup.  Return nil if no window is shown, or if there is no
 need to start the closing timer."
   (cl-case which-key-popup-type
     (minibuffer (which-key/show-buffer-minibuffer act-popup-dim))
-    (side-window (which-key/show-buffer-side-window act-popup-dim))))
+    (side-window (which-key/show-buffer-side-window act-popup-dim))
+    (frame (which-key/show-buffer-frame act-popup-dim))))
 
 (defun which-key/show-buffer-minibuffer (act-popup-dim)
   nil)
@@ -173,10 +199,53 @@ need to start the closing timer."
   (let* ((height (car act-popup-dim))
          (width (cdr act-popup-dim))
          (side which-key-side-window-location)
-         (alist (delq nil (list (when side (cons 'side side))
-                                (when height (cons 'window-height height))
+         (alist (delq nil (list (when height (cons 'window-height height))
                                 (when width (cons 'window-width width))))))
-    (display-buffer which-key--buffer (cons 'display-buffer-in-side-window alist))))
+    ;; Note: `display-buffer-in-side-window' and `display-buffer-in-major-side-window'
+    ;; were added in Emacs 24.3
+
+    ;; If two side windows exist in the same side, `display-buffer-in-side-window'
+    ;; will use on of them, which isn't desirable. `display-buffer-in-major-side-window'
+    ;; will pop a new window, so we use that.
+    ;; +-------------------------+         +-------------------------+
+    ;; |     regular window      |         |     regular window      |
+    ;; |                         |         +------------+------------+
+    ;; +------------+------------+   -->   | side-win 1 | side-win 2 |
+    ;; | side-win 1 | side-win 2 |         |------------+------------|
+    ;; |            |            |         |     which-key window    |
+    ;; +------------+------------+         +------------+------------+
+    ;; (display-buffer which-key--buffer (cons 'display-buffer-in-side-window alist))
+    ;; side defaults to bottom
+    (if (get-buffer-window which-key--buffer)
+        (display-buffer-reuse-window which-key--buffer alist)
+      (display-buffer-in-major-side-window which-key--buffer side 0 alist))))
+
+(defun which-key/show-buffer-frame (act-popup-dim)
+  (let ((orig-window (selected-window))
+        (new-window (if (and (frame-live-p which-key--frame)
+                             (eq which-key--buffer
+                                 (window-buffer (frame-root-window which-key--frame))))
+                        (which-key/show-buffer-reuse-frame)
+                      (which-key/show-buffer-new-frame act-popup-dim))))
+    (fit-frame-to-buffer (window-frame new-window))
+    (select-frame-set-input-focus (window-frame orig-window))
+    (select-window orig-window)
+    (setq which-key--frame (window-frame new-window))
+    new-window))
+
+(defun which-key/show-buffer-new-frame (act-popup-dim)
+  (let* ((height (car act-popup-dim))
+         (width (cdr act-popup-dim))
+         (frame-params (delq nil (list (when (and height width) (cons 'window-height height))
+                                       (when (and height width) (cons 'window-width width))
+                                       (cons 'minibuffer nil)
+                                       (cons 'name "which-key"))))
+         (alist (list (cons 'pop-up-frame-parameters frame-params)
+                      (cons 'inhibit-switch-frame t))))
+    (display-buffer-pop-up-frame which-key--buffer alist)))
+
+(defun which-key/show-buffer-reuse-frame ()
+  (display-buffer-reuse-window which-key--buffer `((reusable-frames . ,which-key--frame))))
 
 ;; Keep for popwin maybe (Used to work)
 ;; (defun which-key/show-buffer-popwin (height width)
@@ -199,7 +268,8 @@ need to start the closing timer."
 of the intended popup."
   (cl-case which-key-popup-type
     (minibuffer (which-key/minibuffer-max-dimensions))
-    (side-window (which-key/side-window-max-dimensions column-width))))
+    (side-window (which-key/side-window-max-dimensions column-width))
+    (frame (which-key/frame-max-dimensions))))
 
 (defun which-key/minibuffer-max-dimensions ()
   (cons
@@ -223,6 +293,9 @@ of the intended popup."
        (min which-key-side-window-max-width column-width)
      (frame-width))))
 
+(defun which-key/frame-max-dimensions ()
+  (cons which-key-frame-max-height which-key-frame-max-width))
+
 ;; Buffer contents functions
 
 (defun which-key/get-formatted-key-bindings (buffer key)
@@ -287,7 +360,9 @@ of the intended popup."
       (if (eq which-key-popup-type 'minibuffer)
           (let (message-log-max) (message "%s" (car pages)))
         (with-current-buffer which-key--buffer
-          (insert (car pages)))))
+          (erase-buffer)
+          (insert (car pages))
+          (goto-char (point-min)))))
     (cons act-height act-width)))
 
 (defun which-key/replace-strings-from-alist (replacements)